#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <linux/input.h>

//  应用层操作i2c2个头文件
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <sys/ioctl.h>


/***
 * 26..如何在应用程序中使用I2C: ft5x05_read_msg、ft5x05_write_msg 通过  ioctl 实现
 *  应用程序中通过i2c_msg 封装数据包
 *  读函数
 */ 
int ft5x05_read_ioctl_msg(int fd, unsigned char slave_addr,unsigned char reg_addr){
    unsigned char data;
	struct  i2c_rdwr_ioctl_data i2c_msgs;
	int ret; 
    struct i2c_msg dev_msgs[]={
        [0]={   //片选i2c
            .addr= slave_addr,
            .flags =0,
            .len= sizeof(reg_addr),
            .buf = &reg_addr,
        },
        [1]={
            .addr= slave_addr,
            .flags =1,
            .len= sizeof(data),
            .buf = &data,
        },
    };
	i2c_msgs.msgs= dev_msgs;
	i2c_msgs.nmsgs= 2;    //2个上面
// 应用程序中对i2c进一步封装，调用i2c_rdwr_ioctl_data  这个结构体
	  /* This is the structure as used in the I2C_RDWR ioctl call */
// struct i2c_rdwr_ioctl_data {
// 	struct i2c_msg __user *msgs;	/* pointers to i2c_msgs */
// 	__u32 nmsgs;			/* number of i2c_msgs */
// };
//调用ioctl 会执行驱动中的 ioctl函数 
ret = ioctl(fd,I2C_RDWR, &i2c_msgs);

if(ret < 0 ){
	printf("read error \n");
}

    return data;
}


/** 
  *  写函数
  */

void ft5x05_write_ioctrl_msg(int fd, unsigned char slave_addr,unsigned char reg_addr,unsigned char data ,int len ){
   unsigned char buff[256];
   struct  i2c_rdwr_ioctl_data i2c_msgs;
   int ret; 
   struct i2c_msg dev_msgs[]={
        [0]={   //片选i2c
            .addr= slave_addr,
            .flags =0,
            .len= len+1,
            .buf = buff,
        },
     };  
	 buff[0]=reg_addr;
     memcpy(&buff[1],&data,len);
	i2c_msgs.msgs= dev_msgs;
	i2c_msgs.nmsgs= 1;    //1个上面
    //调用ioctl 会执行驱动中的 ioctl函数 
	ret = ioctl(fd,I2C_RDWR,&i2c_msgs);
    if(ret < 0){
			printf("write error \n");
	}
}





// 26..如何在应用程序中使用I2C  【io-ctrl使用】 
int main1(void)
{
/***
 *  i2c控制器的节点！！ 
crw------- 1 root   root   89,   0 2024-04-23 10:53 i2c-0
crw-rw---- 1 system system 89,   1 2024-04-23 10:53 i2c-1
crw------- 1 root   root   89,   2 2024-04-23 10:53 i2c-2
crw------- 1 root   root   89,   3 2024-04-23 10:53 i2c-3
crw------- 1 root   root   89,   5 2024-04-23 10:53 i2c-5
 */   
    int fd; 
    int ID_G_THGROUP;
    fd = open("/dev/i2c-2", O_RDWR);
    if(fd<0){
        printf(" open error   \n");
        return fd;
    }
    // 片选0x38  寄存器 0x80 写入 0x55
    ft5x05_write_ioctrl_msg(fd,0x38,0x80,0x55,1);

    ID_G_THGROUP  = ft5x05_read_ioctl_msg(fd,0x38,0x80);

    printf(" data: %#x", ID_G_THGROUP );  // 打印读出0x55
	return 0;
 }




/*
 * 
 *27.为什么在应用程序中可以使用ioctl控制i2c 
 *  i2c控制器驱动已经实现了ioctl,read,write
 *
 *  接口在kernel\drivers\i2c\i2c-dev.c中 ，把这个驱动编译到内核
 export ARCH=arm64 
make menuconfig
   Device Drivers  --->    I2C support  --->   <*>   I2C device interface 
 *   
 */
void ft5x05_write_msg1(int fd,unsigned char reg_addr,unsigned char data){
     unsigned char wr_data[2];
     wr_data[0]=reg_addr;
     wr_data[1]=data;
     write(fd,wr_data,2);
}
void ft5x05_read_msg1(int fd, unsigned char reg_addr){
      unsigned char rd_data[1];
      rd_data[0]=reg_addr;
      write(fd,rd_data,1);
      read(fd,rd_data,1);
      printf("reg value is %#x \n", rd_data[0]);

}




//29.  在应用程序中使用  read,write实现i2c通信
//不加载之前的驱动程序
int main(void)
{
    int fd; 
    fd = open("/dev/i2c-2", O_RDWR);
    if(fd<0){
        printf(" open error   \n");
        return fd;
    }
	//cmd:I2C_SLAVE_FORCE  这个命令的作用就是给 i2c_client.addr= 0x38  片选外设
	//这里ioctl使用I2C_SLAVE_FORCE 命令，给i2c设置地址，不读写

    ioctl(fd,I2C_SLAVE_FORCE, 0x38 );  
    ft5x05_write_msg1(fd,0x80,0x66);
    ft5x05_read_msg1(fd,0x80);   //如果打印0x66 成功了
}
